<script setup lang="ts">
import { CanvasHTMLAttributes, onMounted, onUnmounted, onUpdated, ref } from 'vue';
import { Application, Assets, Sprite } from 'pixi.js';
import * as PIXI from 'pixi.js';
import axios from 'redaxios';
import {
    ConvertCurvePointToControlPoint, ConvertCurvePointToControlPointXY, ProfileInfoResponseItem,
    VecPoint, ConvertControlPointToCurvePoint, TempatureListResponseItem, clampN, CalcYPosWithX
} from '../webApi';
import { useMessage } from 'naive-ui';

const props = defineProps<{ thisId: string, profile: ProfileInfoResponseItem, tempature: number | undefined }>();



const message = useMessage();
function onUpdate() {
    message.info(props.thisId + "更新 ！");
    apiUpdateCurvePoints();
}
let existsProile = JSON.stringify(props.profile);
onUpdated(() => {
    const nextP = JSON.stringify(props.profile);
    if (nextP != existsProile) {
        existsProile = nextP;
        rebuildXgList();
        console.log('diffrent .. ', nextP == existsProile, props.profile);
    }
});

const app = new Application({ antialias: true, background: '#484848', });
type DragableHandler = { thing: PIXI.Graphics, info: { tag: 'fixed' | 'dyn', rxy: { x: number, y: number } } };
let xgList: DragableHandler[] = [];
let dragTarget: DragableHandler | null = null;

async function apiUpdateCurvePoints() {
    resortXGlist();
    axios.post("/api/profile/setCurvePoints", {
        id: props.profile.SensorId,
        curvePoints: xgList.map(item => ({
            X: item.info.rxy.x,
            Y: item.info.rxy.y,
        })),
    });
}

function resortXGlist() {
    xgList.sort((a, b) => {
        if (a.info.rxy.x === b.info.rxy.x) {

            if (a.info.tag == 'fixed' && b.info.tag == 'dyn') return -1;
            if (b.info.tag == 'fixed' && a.info.tag == 'dyn') return 1;

            return -(a.info.rxy.y - b.info.rxy.y);
        }
        return a.info.rxy.x - b.info.rxy.x;
    });
}
function genRBLT() {
    // const RBCorner = { X: app.view.width - 10, Y: +10 };
    // const LTCorner = { X: +10, Y: app.view.height - 10 };
    const RBCorner = { X: app.renderer.width - 10, Y: +10 };
    const LTCorner = { X: +10, Y: app.renderer.height - 10 };

    return { RBCorner, LTCorner };
}

function resetHandlerPosition(theCircle: PIXI.DisplayObject, vp: VecPoint) {
    const { RBCorner, LTCorner } = genRBLT();
    const pp = ConvertCurvePointToControlPoint(RBCorner, LTCorner, vp);
    theCircle.position.set(pp.X, pp.Y);
}

function addXgAt(handler: {
    PropsX: number;
    PropsY: number;
}, tag: 'fixed' | 'dyn') {
    const thing = new PIXI.Graphics();
    if (tag == 'fixed') {
        thing.beginFill(0xffffff, 0.2);
        thing.drawCircle(0, 0, 10); // circle
    } else {
        thing.beginFill(0xffffff, 0.5);
        thing.drawCircle(0, 0, 10); // circle
    }
    // thing.beginFill(0xff0000);
    const dt = {
        info: { tag, rxy: { x: handler.PropsX, y: handler.PropsY } },
        thing,
    };
    thing.on('pointerdown', (event: PIXI.FederatedPointerEvent) => {
        if (event.button == 0) {
            thing.alpha = 0.5;
            dragTarget = dt;
            app.stage.on('pointermove', onDragMove);
        }
    }, thing);
    thing.eventMode = 'static';
    thing.cursor = 'pointer';
    resetHandlerPosition(thing, { X: handler.PropsX, Y: handler.PropsY });
    app.stage.addChild(thing);

    xgList.push(dt);
    resortXGlist();
}

function onDragMove(event: PIXI.FederatedPointerEvent) {
    if (dragTarget) {
        let originalPos = dragTarget.thing.position.clone();
        dragTarget.thing.parent.toLocal(event.global, undefined, dragTarget.thing.position);
        if (dragTarget.info.tag == 'fixed') {
            dragTarget.thing.position.x = originalPos.x;
        }
        const { RBCorner, LTCorner } = genRBLT();
        const inPos = ConvertControlPointToCurvePoint(RBCorner, LTCorner, {
            X: dragTarget.thing.x,
            Y: dragTarget.thing.y,
        });

        const ntXy = ConvertCurvePointToControlPointXY(
            RBCorner, LTCorner,
            clampN(inPos.X, 1, 99), clampN(inPos.Y, 0, 100),
        );

        if (dragTarget.info.tag == 'dyn') {
            if (inPos.X < 1 || inPos.X > 99 || inPos.Y < 0 || inPos.Y > 100) {
                dragTarget.thing.x = ntXy.X;
                dragTarget.thing.y = ntXy.Y;
            }
        }

        if (dragTarget.info.tag == 'fixed') {
            if (inPos.X < 0 || inPos.X > 100 || inPos.Y < 0 || inPos.Y > 100) {
                dragTarget.thing.x = ntXy.X;
                dragTarget.thing.y = ntXy.Y;
            }
        }
    }
}

function rebuildXgList() {

    // remove old
    dragTarget = null;
    for (const item of xgList) {
        app.stage.removeChild(item.thing);
    }
    xgList = [];

    const totalPFList = props.profile?.curvePoints || [];
    totalPFList.sort((a, b) => a.PropsX - b.PropsY);
    if (totalPFList.length < 2) {
        totalPFList.push({ PropsX: 0, PropsY: 0, });
        totalPFList.push({ PropsX: 100, PropsY: 100, });
    }
    let handlerCount = 0;
    for (const handler of totalPFList) {
        addXgAt(handler, ((handlerCount == 0 || handlerCount === (totalPFList.length - 1)) ? 'fixed' : "dyn"));
        handlerCount++;
    }
}

function init() {
    function onParentElementResize() {
        const parentEle = (document.querySelector('#' + props.thisId)! as any);
        var w = parentEle.clientWidth;
        var h = parentEle.clientHeight;

        if (Math.abs(app.renderer.width - w) < 5 && Math.abs(app.renderer.height - h) < 10) {
            return;
        }

        console.log(app.renderer.width, app.renderer.height, w, h);
        app.renderer.resize(w, h);

        console.log();
        // 將畫面的正中間放在 app.renderer 一半寬高的位置
        // app.stage.x = app.renderer.width * 0.5;
        // app.stage.y = app.renderer.height * 0.5;
    }
    onParentElementResize();
    const parentEle = (document.querySelector('#' + props.thisId)! as any);
    parentEle.addEventListener(`contextmenu`, (e: any) => e.preventDefault());
    parentEle.appendChild(app.view);



    app.stage.eventMode = 'static';
    app.stage.hitArea = app.screen;
    // app.stage.on('pointerup', onDragEnd);
    app.stage.on('pointerupoutside', onDragEnd);

    function onDragEnd(event: PIXI.FederatedPointerEvent) {
        if (dragTarget) {
            // set
            const { RBCorner, LTCorner } = genRBLT();
            const inPos = ConvertControlPointToCurvePoint(RBCorner, LTCorner, {
                X: dragTarget.thing.x,
                Y: dragTarget.thing.y,
            });
            if (Math.abs(dragTarget.info.rxy.x - inPos.X) > 1 || Math.abs(dragTarget.info.rxy.y - inPos.Y) > 1) {

                dragTarget.info.rxy = {
                    x: inPos.X,
                    y: inPos.Y,
                };
                onUpdate();
            }
            app.stage.off('pointermove', onDragMove);
            dragTarget.thing.alpha = 1;
            dragTarget = null;
        }
    }


    const thingIndicator = new PIXI.Graphics();
    app.stage.addChild(thingIndicator);
    const thingIndicatorText温度 = new PIXI.Text('100℃');
    thingIndicatorText温度.style.fontSize = 16;
    thingIndicatorText温度.style.fill = '#FFFFFF';
    app.stage.addChild(thingIndicatorText温度);
    const thingIndicatorText风速 = new PIXI.Text('100%');
    thingIndicatorText风速.style.fontSize = 16;
    thingIndicatorText风速.style.fill = '#FFFFFF';
    app.stage.addChild(thingIndicatorText风速);

    const thingIndicatorText温度Dyn = new PIXI.Text('');
    thingIndicatorText温度Dyn.style.fontSize = 16;
    thingIndicatorText温度Dyn.style.fill = '#990000';
    app.stage.addChild(thingIndicatorText温度Dyn);

    rebuildXgList();

    app.stage.on('rightclick', (e: PIXI.FederatedPointerEvent) => {

        console.log(e);
        const rightClick = (e.button === 2);
        e.preventDefault();
        const tToRemove = xgList.find(item => item.thing === e.target);
        if (tToRemove && tToRemove.info.tag != 'fixed') {
            xgList = xgList.filter(item => item !== tToRemove);
            app.stage.removeChild(tToRemove.thing);
            onUpdate();
        }
    });
    app.stage.on('click', (e: PIXI.FederatedPointerEvent) => {
        if (dragTarget) {
            onDragEnd(e);
            return;
        }
        const leftClick = (e.button === 0);
        const middelClick = (e.button === 1);
        const rightClick = (e.button === 2);

        console.log(e.getCoalescedEvents());
        e.preventDefault();
        console.log(e);
        console.log(
            'click',
            e.target,
            e.getModifierState('Control'),
            e.button,
            e.getLocalPosition(app.stage), '|',
            e.x, e.y
        );
        ;
        if (dragTarget) {
            return;
        }


        if (leftClick && e.target === app.stage) {
            const lcp = e.getLocalPosition(app.stage);
            const { RBCorner, LTCorner } = genRBLT();
            const rxy = ConvertControlPointToCurvePoint(RBCorner, LTCorner, { X: lcp.x, Y: lcp.y });
            addXgAt({
                PropsX: rxy.X, PropsY: rxy.Y
            }, 'dyn');
            onUpdate();
        }
    });


    function resetThingShape() {
        const { RBCorner, LTCorner } = genRBLT();
        const p左下角 = ConvertCurvePointToControlPointXY(RBCorner, LTCorner, 0, 0);
        const p左上角 = ConvertCurvePointToControlPointXY(RBCorner, LTCorner, 0, 100);
        const p右下角 = ConvertCurvePointToControlPointXY(RBCorner, LTCorner, 100, 0);
        const p右上角 = ConvertCurvePointToControlPointXY(RBCorner, LTCorner, 100, 100);
        thingIndicator.clear();
        thingIndicator.lineStyle(1, 0xcccccc, 1);

        thingIndicator.beginFill(0xffFF00, 0.5);
        thingIndicator.moveTo(p左下角.X, p左下角.Y);
        thingIndicator.lineTo(p左上角.X, p左上角.Y);
        thingIndicator.closePath();

        thingIndicator.beginFill(0xffFF00, 0.5);
        thingIndicator.moveTo(p左下角.X, p左下角.Y);
        thingIndicator.lineTo(p右下角.X, p右下角.Y);
        thingIndicator.closePath();
        // thingIndicator.drawCircle(p右下角.X, p右下角.Y, 5);

        // sort
        resortXGlist();
        if (xgList.length >= 2) {
            const p左下角ext = ConvertCurvePointToControlPointXY(RBCorner, LTCorner, -60, 0);
            const p左上角ext = ConvertCurvePointToControlPointXY(RBCorner, LTCorner, -60, 100);
            const p右下角ext = ConvertCurvePointToControlPointXY(RBCorner, LTCorner, 160, 0);
            const p右上角ext = ConvertCurvePointToControlPointXY(RBCorner, LTCorner, 160, 100);
            thingIndicator.lineStyle(0, 0xcccccc, 0);
            thingIndicator.beginFill(0xFFFFFF, 0.2);
            thingIndicator.moveTo(p左下角ext.X, p左下角ext.Y);
            thingIndicator.lineTo(p左下角ext.X, xgList[0].thing.y);
            for (const item of xgList) {
                if (item !== dragTarget) {
                    const gXY = ConvertCurvePointToControlPointXY(RBCorner, LTCorner, item.info.rxy.x, item.info.rxy.y);
                    item.thing.x = gXY.X;
                    item.thing.y = gXY.Y;
                }
                thingIndicator.lineTo(item.thing.x, item.thing.y);
            }
            thingIndicator.lineTo(p右下角ext.X, xgList[xgList.length - 1].thing.y);
            thingIndicator.lineTo(p右下角ext.X, p右下角ext.Y);
            thingIndicator.closePath();
            thingIndicator.drawCircle(p右下角ext.X, p右下角ext.Y, 5);
        }

        // 温度标致
        thingIndicatorText温度Dyn.visible = false;
        if (props.tempature) {
            const rectY = CalcYPosWithX(xgList.map(item => {
                return {
                    X: item.info.rxy.x,
                    Y: item.info.rxy.y,
                }
            }), props.tempature);
            if (rectY) {

                const p1 = ConvertCurvePointToControlPointXY(RBCorner, LTCorner, props.tempature, 0);
                const p2 = ConvertCurvePointToControlPointXY(RBCorner, LTCorner, props.tempature, rectY);
                thingIndicator.lineStyle(1, 0xcc0000, 0.5);
                thingIndicator.beginFill(0xFFFFFF, 0.2);
                thingIndicator.moveTo(p1.X, p1.Y);
                thingIndicator.lineTo(p2.X, p2.Y);
                thingIndicator.closePath();

                thingIndicatorText温度Dyn.text = `${props.tempature.toFixed(1)}`;
                thingIndicatorText温度Dyn.visible = true;
                thingIndicatorText温度Dyn.x = p2.X;
                thingIndicatorText温度Dyn.y = p2.Y;
            }
        }

        thingIndicatorText温度.x = p右下角.X - 51;
        thingIndicatorText温度.y = p右下角.Y - 20;
        thingIndicatorText风速.x = p左上角.X;
        thingIndicatorText风速.y = p左上角.Y;
    }

    app.ticker.add(() => {
        onParentElementResize();
        resetThingShape();
    });
}


onMounted(() => {
    init();
});
onUnmounted(() => {
    app.destroy();
});
</script>

<template>
    <div>
        <div :id="props.thisId"
            style="width: 100%; height: 300px; border-radius: 5px; overflow: hidden; pointer-events: all;">
        </div>
    </div>
</template>